package com.rajaev.dtu.tractor.app.processor;

import com.rajaev.dtu.tractor.app.service.FaultService;
import com.rajaev.dtu.tractor.domain.entity.BatteryPo;
import com.rajaev.dtu.tractor.domain.entity.DeviceFaultRecord;
import com.rajaev.dtu.tractor.domain.entity.SnotiMessage;
import com.rajaev.dtu.tractor.domain.repository.redis.FaultCodeRedisRepository;
import com.rajaev.dtu.tractor.domain.vo.FaultDetailVo;
import com.rajaev.dtu.tractor.infrastructure.base.enums.SnotiEventType;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Component
public class DeviceFaultProcessor {

    private static String fault_key = "B_DCXTGZDM";

    @Autowired
    FaultService faultService;

    @Autowired
    FaultCodeRedisRepository faultCodeRedisRepository;

    /**
     * 根据报文的信息，对报文里的故障报文进行解析，然后将报文的故障内容进行入库
     *
     * @param snotiMessage
     */
    public void doProcessDeviceFaultFromSnotiMessage(SnotiMessage snotiMessage) {
        long thisTimeStamp = new BigDecimal(snotiMessage.getCreated_at()).longValue();
        BatteryPo batteryPo = SnotiMessageContextHolder.getTargetBattery();

        SnotiEventType snotiEventType = SnotiEventType.getType(snotiMessage.getEvent_type());
        if (!SnotiEventType.KV.equals(snotiEventType)) {
            return;
        }
        //判断此报文是否有故障信息
        if (snotiMessage.getData().containsKey(fault_key)) {
            short faultCode = snotiMessage.getData().getShort(fault_key);
            if (faultCode != 0) {
                if (!faultCodeRedisRepository.isFaultSaved(batteryPo.getVin(), String.valueOf(faultCode))) {
                    //在mysql中插入一条故障发生的记录。
                    faultService.addFaultRecord(batteryPo.getId(), faultCode, new Date(new BigDecimal(snotiMessage.getCreated_at()).longValue() * 1000));
                }
                faultCodeRedisRepository.refreshFaultCode(batteryPo.getVin(), String.valueOf(faultCode), thisTimeStamp);
            } else {
                faultCodeRedisRepository.clearDeviceFault(batteryPo.getVin());
            }
        }
    }

    @Scheduled(fixedRate = 1000 * 60)
    public void checkDeviceFaultIsOver() {
        List<FaultDetailVo> list = faultService.selectAllNotOveredFault();
        List<FaultDetailVo> hasOveredFaultList = new ArrayList<>();
        for (FaultDetailVo faultDetailVo : list) {
            Optional<DeviceFaultRecord> optional = faultCodeRedisRepository
                    .getDeviceFault(faultDetailVo.getVin(), String.valueOf(faultDetailVo.getFaultCode()));
            //当故障已经解除，则在mysql中修改该故障的状态为已经解除
            if (optional.isPresent()) {
                DeviceFaultRecord deviceFaultRecord = optional.get();
                if (!deviceFaultRecord.isNotOver()) {
                    faultCodeRedisRepository.deleteDeviceFaultFromRedis(faultDetailVo.getVin(), deviceFaultRecord.getCode());
                    hasOveredFaultList.add(faultDetailVo);
                }
            } else {
                //该故障在redis当中无缓存，须在数据库当中修改为解除
                hasOveredFaultList.add(faultDetailVo);
            }
            if (CollectionUtils.isNotEmpty(hasOveredFaultList)) {
                faultService.setFaultReset(hasOveredFaultList);
            }

        }
    }
}
